﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace TimedScreenSaver
{
    public partial class SettingsForm : Form
    {
        #region Fields

        private const int MarginPosition = 50;
        private const int ButtonsArrayLength = 9;
        private const int DateUnderTextInterval = 5;
        
        private readonly Color _selectedButtonBackColor = Color.Green;
        private readonly Button[] _buttons = new Button[ButtonsArrayLength];

        private ScreenPosition _screenPosition = ScreenPosition.Custom;

        #endregion

        #region Constructor

        public SettingsForm()
        {
            InitializeComponent();
        }

        #endregion

        #region Methods

        private void LoadSettings()
        {
            Settings.Instance.LoadSettings();

            contentTextBox.Text = Settings.Instance.ContentText;
            timeRadioBtn.Checked = Settings.Instance.IsTimeDisplayed;
            textRadioBtn.Checked = !timeRadioBtn.Checked;
            dateCheckBox.Checked = Settings.Instance.IsDateDisplayed;

            if (Settings.Instance.IsTimeDisplayed)
            {
                secondsCheckBox.Checked = Settings.Instance.IsLongTimeDisplayed;
            }
            if (Settings.Instance.IsDateDisplayed)
            {
                yearCheckBox.Visible = true;
                yearCheckBox.Checked = Settings.Instance.IsYearDisplayed;

                dateLbl.Visible = true;
                dateLbl.Text = Settings.Instance.DateText;
            }

            SetFont(Settings.Instance.FontText);
            SetBackColor(Settings.Instance.BackColor);
            SetFontColor(Settings.Instance.FontColor);

            _screenPosition = Settings.Instance.PositionOnScreen;

            if (_screenPosition == ScreenPosition.Custom)
            {
                customPositionRadioBtn.Checked = true;
            }
            else
            {
                SetButtonSelected(_screenPosition);
            }

            UpdateTextAndPosition();
        }

        private static void SaveSettings()
        {
            Settings.Instance.SaveSettings();
        }

        private void PopulateButtonsArray()
        {
            _buttons[0] = button1;
            _buttons[1] = button2;
            _buttons[2] = button3;
            _buttons[3] = button4;
            _buttons[4] = button5;
            _buttons[5] = button6;
            _buttons[6] = button7;
            _buttons[7] = button8;
            _buttons[8] = button9;
        }

        private Point GetContentTextPosition(ScreenPosition screenPosition)
        {
            switch (screenPosition)
            {
                case ScreenPosition.Custom:
                    return Settings.Instance.CustomScreenPosition;
                case ScreenPosition.TopLeft:
                    return new Point(MarginPosition, MarginPosition);
                case ScreenPosition.TopCenter:
                    return new Point((backColorPanel.Width - contentLbl.Width) / 2, MarginPosition);
                case ScreenPosition.TopRight:
                    return new Point((backColorPanel.Width - contentLbl.Width - MarginPosition), MarginPosition);
                case ScreenPosition.MidLeft:
                    return new Point(MarginPosition, (backColorPanel.Height - contentLbl.Height) / 2);
                case ScreenPosition.MidRight:
                    return new Point((backColorPanel.Width - contentLbl.Width - MarginPosition), (backColorPanel.Height - contentLbl.Height) / 2);
                case ScreenPosition.BottLeft:
                    return new Point(MarginPosition, (backColorPanel.Height - contentLbl.Height - MarginPosition));
                case ScreenPosition.BottCenter:
                    return new Point((backColorPanel.Width - contentLbl.Width) / 2, (backColorPanel.Height - contentLbl.Height - MarginPosition));
                case ScreenPosition.BottRight:
                    return new Point((backColorPanel.Width - contentLbl.Width - MarginPosition), (backColorPanel.Height - contentLbl.Height - MarginPosition));
                //case ScreenPosition.MidCenter:
                default:
                    return new Point((backColorPanel.Width - contentLbl.Width) / 2, (backColorPanel.Height - contentLbl.Height) / 2);
            }
        }

        private Point GetDateTextPosition(Point contentPoint)
        {
            int lenDiff = Math.Abs(dateLbl.Width - contentLbl.Width) / 2;
            int xPos;
            if (contentLbl.Width < dateLbl.Width)
            {
                xPos = contentPoint.X - lenDiff;
            }
            else
            {
                xPos = contentPoint.X + lenDiff;
            }

            return new Point(xPos, contentPoint.Y + contentLbl.Height + DateUnderTextInterval);
        }

        private void CheckTimerStatus()
        {
            if (timer == null) return;

            if (timeRadioBtn.Checked)
            {
                contentTextBox.Visible = false;
                timePatternGroupBox.Visible = true;
                Settings.Instance.IsTimeDisplayed = true;
                UpdateContentAndDateText();
                timer.Start();
            }
            else
            {
                timer.Stop();
                timePatternGroupBox.Visible = false;
                contentTextBox.Visible = true;
                Settings.Instance.IsTimeDisplayed = false;
                contentLbl.Text = Settings.Instance.ContentText;
            }

            RecalculateTextPosition();
        }

        private void CheckTimePattern()
        {
            Settings.Instance.IsLongTimeDisplayed = secondsCheckBox.Checked;
            UpdateTextAndPosition();
        }

        private void CheckSelectedPosition()
        {
            if (definedPositionRadioBtn.Checked)
            {
                Settings.Instance.PositionOnScreen = _screenPosition;
                customPositionLbl.Visible = false;
                customPositionBtn.Visible = false;
                positionPanel.Visible = true;
                SetButtonSelected(_screenPosition);
            }
            else 
            {
                if (Settings.Instance.PositionOnScreen != ScreenPosition.Custom)
                {
                    Settings.Instance.PositionOnScreen = ScreenPosition.Custom;
                    Settings.Instance.CustomScreenPosition = contentLbl.Location;
                }

                customPositionLbl.Visible = true;
                customPositionBtn.Visible = true;
                positionPanel.Visible = false;
            }
        }

        private void UpdateTextAndPosition()
        {
            UpdateContentAndDateText();
            
            RecalculateTextPosition();
        }

        private void RecalculateTextPosition()
        {
            if (string.IsNullOrWhiteSpace(contentTextBox.Text) &&
                !dateCheckBox.Checked) return;

            contentLbl.Location = GetContentTextPosition(Settings.Instance.PositionOnScreen);
            if (dateLbl.Visible)
            {
                dateLbl.Location = GetDateTextPosition(contentLbl.Location);
            }
        }

        private static ScreenPosition GetScreePosition(string positionNumber)
        {
            return (ScreenPosition)Convert.ToInt32(positionNumber);
        }

        private void SetButtonSelected(ScreenPosition position)
        {
            Button btn = null;

            switch (position)
            {
                case ScreenPosition.Custom:
                    UpdateTextAndPosition();
                    break;
                case ScreenPosition.TopLeft:
                    ResetButtonsBackground(button1);
                    break;
                case ScreenPosition.TopCenter:
                    ResetButtonsBackground(button2);
                    break;
                case ScreenPosition.TopRight:
                    ResetButtonsBackground(button3);
                    break;
                case ScreenPosition.MidLeft:
                    ResetButtonsBackground(button4);
                    break;
                case ScreenPosition.MidCenter:
                    ResetButtonsBackground(button5);
                    break;
                case ScreenPosition.MidRight:
                    ResetButtonsBackground(button6);
                    break;
                case ScreenPosition.BottLeft:
                    ResetButtonsBackground(button7);
                    break;
                case ScreenPosition.BottCenter:
                    ResetButtonsBackground(button8);
                    break;
                case ScreenPosition.BottRight:
                    ResetButtonsBackground(button9);
                    break;
                default:
                    ResetButtonsBackground(btn);
                    break;
            }
        }
        
        private void ResetButtonsBackground(Button current = null)
        {
            foreach (Button button in _buttons)
            {
                if (button == current) continue;
                button.ResetBackColor();
            }

            if (current != null)
            {
                current.BackColor = _selectedButtonBackColor;
            }
        }

        private void SetBackColor(Color backColor)
        {
            contentLbl.BackColor = backColor;
            dateLbl.BackColor = backColor;
            backColorPanel.BackColor = backColor;
        }

        private void SetFontColor(Color fontColor)
        {
            contentLbl.ForeColor = fontColor;
            dateLbl.ForeColor = fontColor;
        }

        private void SetFont(Font newFont)
        {
            contentLbl.Font = newFont;
            dateLbl.Font = new Font(newFont.FontFamily, newFont.Size / Settings.Instance.DateFontSizeFactor, GraphicsUnit.Point);
        }

        private void UpdateContentAndDateText()
        {
            contentLbl.Text = Settings.Instance.TimeText;
            if (dateLbl.Visible)
            {
                dateLbl.Text = Settings.Instance.DateText;
            }
        }

        #region Hendlers

        private void OkButtonClick(object sender, EventArgs e)
        {
            SaveSettings();
            Close();
        }

        private void CancelButtonClick(object sender, EventArgs e)
        {
            Close();
        }

        private void SettingsFormLoad(object sender, EventArgs e)
        {
            PopulateButtonsArray();
            LoadSettings();

            CheckTimerStatus();
        }

        private void TimerTick(object sender, EventArgs e)
        {
            UpdateContentAndDateText();
        }

        private void SettingsFormFormClosing(object sender, FormClosingEventArgs e)
        {
            if (timer != null) timer.Stop();
        }

        private void SettingsFormSizeChanged(object sender, EventArgs e)
        {
            RecalculateTextPosition();
        }

        private void ContentTypeChanged(object sender, EventArgs e)
        {
            CheckTimerStatus();
        }

        private void TimePatternChanged(object sender, EventArgs e)
        {
            CheckTimePattern();
        }

        private void ContentTextBoxTextChanged(object sender, EventArgs e)
        {
            contentLbl.Text = contentTextBox.Text;
            if (textRadioBtn.Checked)
            {
                Settings.Instance.ContentText = contentTextBox.Text;
            }

            RecalculateTextPosition();
        }

        private void DefinedPositionRadioBtnCheckedChanged(object sender, EventArgs e)
        {
            CheckSelectedPosition();
        }

        private void CustomPositionRadioBtnCheckedChanged(object sender, EventArgs e)
        {
            CheckSelectedPosition();
        }

        private void PositionButtonClick(object sender, EventArgs e)
        {
            var currentButton = (Button)sender;
            ResetButtonsBackground(currentButton);

            Settings.Instance.PositionOnScreen = GetScreePosition(currentButton.Name.Substring(6, 1));
            RecalculateTextPosition();
        }

        private void FontBtnClick(object sender, EventArgs e)
        {
            fontDialog.ShowColor = true;
            fontDialog.Color = contentLbl.ForeColor;
            fontDialog.Font = contentLbl.Font;
            
            if (fontDialog.ShowDialog() == DialogResult.OK)
            {
                SetFont(fontDialog.Font);
                SetFontColor(fontDialog.Color);
                
                Settings.Instance.FontText = fontDialog.Font;
                Settings.Instance.FontColor = fontDialog.Color;
            }
        }

        private void ColorBtnClick(object sender, EventArgs e)
        {
            // Sets the initial color select to the current text color.
            colorDialog.Color = contentLbl.ForeColor;

            // Update the text box color if the user clicks OK 
            if (colorDialog.ShowDialog() == DialogResult.OK)
            {
                SetBackColor(colorDialog.Color);
                Settings.Instance.BackColor = colorDialog.Color;
            }
        }

        private void DateCheckBoxCheckedChanged(object sender, EventArgs e)
        {
            dateLbl.Visible = dateCheckBox.Checked;
            yearCheckBox.Visible = dateCheckBox.Checked;
            Settings.Instance.IsDateDisplayed = dateCheckBox.Checked;
            UpdateTextAndPosition();
        }

        private void CustomPositionBtnClick(object sender, EventArgs e)
        {
            var screenSaverForm = new ScreenSaverForm(Screen.PrimaryScreen.Bounds) {IsTestMode = true};
            screenSaverForm.FormClosed += ScreenSaverFormFormClosed;
            screenSaverForm.Show();
        }

        private void ScreenSaverFormFormClosed(object sender, FormClosedEventArgs e)
        {
            RecalculateTextPosition();
        }

        private void YearCheckBoxCheckedChanged(object sender, EventArgs e)
        {
            Settings.Instance.IsYearDisplayed = yearCheckBox.Checked;
            UpdateTextAndPosition();
        }

        #endregion

        #endregion
    }
}
